#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include <algorithm>
#include "include/TcpSocket.hpp"
#include "include/Log.hpp"
#include "Epoller.hpp"
#include "Connection.hpp"

const static int default_maxevents = 64;

/**
 * Reactor：反应堆模式，半同步半异步模式，Linux高并发服务器最常见的模式
 * 事件的产生和事件的派发是异步的，事件什么时候到来并不清楚
 * 处理事件的整个周期是同步的
 * 
 * 打地鼠：打地鼠机->Reactor事件派发，地洞->文件描述符，地鼠->事件，砸地鼠->执行对应回调
*/

class Reactor
{
public:
    Reactor(): _isRunning(false)
    {
        srand(time(nullptr));
    }

    void start()
    {
        _isRunning = true;
        while(_isRunning)
        {
            _epoller.printFdList();
            dispatcher();
        }
        _isRunning = false;
    }

    void dispatcher() //事件派发器，仅做事件派发，不做IO
    {
        int n = _epoller.wait(_revs, default_maxevents, -1);
        for(int i = 0; i < n; i++)
        {
            int fd = _revs[i].data.fd;
            uint32_t events  = _revs[i].events;
            if((events & EPOLLERR) || (events & EPOLLHUP))
            {
                events |= (EPOLLIN|EPOLLOUT); //将所有异常问题，转化为读写错误
            }
            if((events & EPOLLIN) && isConnectionExists(fd) && (_connections[fd]->_read != nullptr))
            {
                _connections[fd]->_read(_connections[fd]); //为读事件，连接存在，回调已设置，则调用回调
            }
            if((events & EPOLLOUT) && isConnectionExists(fd) && (_connections[fd]->_write != nullptr))
            {
                _connections[fd]->_write(_connections[fd]);
            }
        }
    }

    void addConnection(Connection* conn)
    {
        if((conn != nullptr) && !isConnectionExists(conn->getSockFd())) 
        {
            _connections[conn->getSockFd()] = conn;
            log.message(INFO, "addConnection success, fd: %d", conn->getSockFd());
            _epoller.addEvent(conn->getSockFd(), conn->getEvents());
        }
    }

    void addSubReactorConnection(Connection* conn)
    {
        if((conn != nullptr) && !isConnectionExists(conn->getSockFd())) 
        {
            _connections[conn->getSockFd()] = conn;
            log.message(INFO, "addSubReactorConnection success, fd: %d", conn->getSockFd());
            _epoller.addEvent(conn->getSockFd(), conn->getEvents());
        }
    }

    void removeConnection(Connection* conn)
    {
        if((conn != nullptr) && isConnectionExists(conn->getSockFd()))
        {
            _epoller.deletEvent(conn->getSockFd());
            _connections.erase(conn->getSockFd());
        }
    }

    void enableEvent(int fd, bool read, bool write)
    {
        if(!isConnectionExists(fd)) return;
        uint32_t events = (read ? EPOLLIN : 0) | (write ? EPOLLOUT : 0) | EPOLLET;
        _connections[fd]->setEvents(events);
        _epoller.modifyEvent(fd, events);
    }

    bool isConnectionExists(int fd)
    {
        auto it = _connections.find(fd);
        return it != _connections.end();
    }

    Connection* getSubReactorConnection()
    {
        return _connections[_connFds[rand() % _connFds.size()]]; //负载均衡，随机选一个
    }

    void setConnFds(const std::vector<int>& connFds)
    {
        _connFds = connFds;
    }

    ~Reactor()
    {}
private:
    Epoller _epoller;
    std::unordered_map<int, Connection*> _connections;
    std::vector<int> _connFds;
    struct epoll_event _revs[default_maxevents];
    bool _isRunning;
};